package pl.edu.agh.administracja.networkconfig.view;

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.StaxDriver;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JCheckBox;
import javax.swing.JOptionPane;
import pl.edu.agh.administracja.networkconfig.controller.AddressChangedListener;
import pl.edu.agh.administracja.networkconfig.model.*;
import pl.edu.agh.administracja.networkconfig.model.util.ConfigIO;
import pl.edu.agh.administracja.networkconfig.model.util.NetworkInterfacesResolver;
import pl.edu.agh.administracja.networkconfig.model.util.ShellExecutor;

/**
 *
 * @author piotrek
 */
public class NetworkInterfaceDialog extends javax.swing.JDialog {

    private NetworkInterfaceConfig model = null;
    
    private static final XStream xstream;
    
    private FocusListener ipAddressFocusListener;
    private FocusListener maskAddressFocusListener;
    private FocusListener gateAddressFocusListener;
    
    static {
        xstream = new XStream(new StaxDriver());
        xstream.alias("config", NetworkInterfaceConfig.class);
    }
    
    /**
     * Creates new form NetworkInterfaceDialog
     */
    public NetworkInterfaceDialog(java.awt.Frame parent, boolean modal) {
        super(parent, modal);
        initComponents();
        updateView();
        
        addFocusListeners();
    }
    
    private void updateOnButton() {
        if (model.isOn())  {
            onButton.setText("wyłącz");
            onButton.setBackground(Color.GREEN);
        }else {
            onButton.setBackground(Color.RED);
            onButton.setText("włącz");
        }
    }
    
    private void updateView(){
        
        if(model == null){
            setInterfaceViewEnabled(false);
            setWirelessInterfaceViewEnabled(false);
            return;
        }
        
        ipAddressFocusListener = new AddressChangedListener(ipTextInput, model, "ipAddress", false);
        maskAddressFocusListener = new AddressChangedListener(maskTextInput, model, "mask", true);
        gateAddressFocusListener = new AddressChangedListener(gateTextInput, model, "defaultGateway", false);
        
        setInterfaceViewEnabled(true);
        
        if(model.isIpViaDHCP()) {
            dhcpCheckBox.setSelected(true);
            ipTextInput.setEnabled(false);
            maskTextInput.setEnabled(false);
            gateTextInput.setEnabled(false);
        }else{
            dhcpCheckBox.setSelected(false);
        }
        
        updateOnButton();
        
        onButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                String password = PasswordHolder.getPassword();
                
                if(password == null) {
                    JOptionPane.showMessageDialog(null, "Podałeś niewłaściwe hasło!");
                    return;
                }
                
                if (model.isOn()) {
                    ShellExecutor.executeSynchronously("echo '"+ password +"' | sudo -S ifconfig " + model.getName() + " down");
                    model.setOn(false);
                }
                else {
                    ShellExecutor.executeSynchronously("echo '"+password+"' | sudo -S ifconfig " + model.getName() + " up");           
                    model.setOn(true);
                }
                updateOnButton();
        }
        });
        
        if(model.getIpAddress() != null)
            ipTextInput.setText(model.getIpAddress().toString());
        else
            ipTextInput.setText("");
        
        if(model.getMask() != null)
            maskTextInput.setText(model.getMask().toString());
        else
            maskTextInput.setText("");
        
        if(model.getDefaultGateway() != null)
            gateTextInput.setText(model.getDefaultGateway().toString());
        else
            gateTextInput.setText("");
        
        sentTextInput.setText(model.getSent());
        receivedTextInput.setText(model.getReceived());
        
        if(model instanceof WirelessInterfaceConfig){
            
            setWirelessInterfaceViewEnabled(true);
            
            WirelessInterfaceConfig wirelessInterface = (WirelessInterfaceConfig) model;
            WirelessNetwork network = wirelessInterface.getConnectedTo();
            if(network != null){
                wirelessNameTextField.setText(network.getESSID());
                wirelessSignalStrengthTextField.setText(network.getQuality());
            }
            else{
                wirelessNameTextField.setText("");
                wirelessSignalStrengthTextField.setText("");
            }
        }
    }
    
//    private void updateModel(){
//        if(model != null){
//            
//            model.setIpViaDHCP(dhcpCheckBox.isSelected());
//            
//            if(ipTextInput.getText().equals(IpV4Address.EMPTY_ADDRESS))
//                model.setIpAddress(null);
//            else
//                model.setIpAddress(IpV4Address.fromString(ipTextInput.getText()));
//            
//            if(maskTextInput.getText().equals(IpV4Address.EMPTY_ADDRESS))
//                model.setMask(null);
//            else
//                model.setMask(IpV4Address.fromString(maskTextInput.getText()));
//            
//            if(gateTextInput.getText().equals(IpV4Address.EMPTY_ADDRESS))
//                model.setDefaultGateway(null);
//            else
//                model.setDefaultGateway(IpV4Address.fromString(gateTextInput.getText()));
//            
//        }
//    }
    
    private void setInterfaceViewEnabled(boolean enabled){
        
        dhcpCheckBox.setEnabled(enabled);
        ipTextInput.setEnabled(enabled);
        maskTextInput.setEnabled(enabled);
        gateTextInput.setEnabled(enabled);
        sentTextInput.setEnabled(enabled);
        receivedTextInput.setEnabled(enabled);
        
        saveInterfaceButton.setEnabled(enabled);
        
    }
    
    private void setWirelessInterfaceViewEnabled(boolean enabled){
        wirelessNameTextField.setEnabled(enabled);
        wirelessSignalStrengthTextField.setEnabled(enabled);
        
        //changeWirelessButton.setEnabled(enabled);
    }

    @Override
    public void setVisible(boolean b) {
        if(b) 
            loadInterfaces();
        super.setVisible(b);
    }
    
    private void loadInterfaces(){
        
        interfacesComboBox.removeAllItems();
        for(NetworkInterfaceConfig _interface : NetworkInterfacesResolver.getInterfaces())
        {
            interfacesComboBox.addItem(_interface);
        }
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        jPanel5 = new javax.swing.JPanel();
        headerInterfaceConfig = new javax.swing.JLabel();
        interfacesComboBox = new javax.swing.JComboBox();
        jPanel1 = new javax.swing.JPanel();
        dhcpCheckBox = new javax.swing.JCheckBox();
        emptyPanel = new javax.swing.JPanel();
        onButton = new javax.swing.JButton();
        jLabel2 = new javax.swing.JLabel();
        ipTextInput = new javax.swing.JTextField();
        jLabel3 = new javax.swing.JLabel();
        maskTextInput = new javax.swing.JTextField();
        jLabel4 = new javax.swing.JLabel();
        gateTextInput = new javax.swing.JTextField();
        jLabel5 = new javax.swing.JLabel();
        sentTextInput = new javax.swing.JTextField();
        jLabel6 = new javax.swing.JLabel();
        receivedTextInput = new javax.swing.JTextField();
        jPanel4 = new javax.swing.JPanel();
        saveInterfaceButton = new javax.swing.JButton();
        loadInterfaceButton = new javax.swing.JButton();
        applyConfigButton = new javax.swing.JButton();
        jPanel10 = new javax.swing.JPanel();
        jPanel2 = new javax.swing.JPanel();
        jLabel1 = new javax.swing.JLabel();
        jPanel7 = new javax.swing.JPanel();
        wirelessName = new javax.swing.JLabel();
        wirelessNameTextField = new javax.swing.JTextField();
        wirelessSignalStrength = new javax.swing.JLabel();
        wirelessSignalStrengthTextField = new javax.swing.JTextField();
        jPanel3 = new javax.swing.JPanel();
        changeWirelessButton = new javax.swing.JButton();

        setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
        getContentPane().setLayout(new javax.swing.BoxLayout(getContentPane(), javax.swing.BoxLayout.Y_AXIS));

        headerInterfaceConfig.setFont(new java.awt.Font("Dialog", 1, 24)); // NOI18N
        headerInterfaceConfig.setText("Zarządzaj interfejsami");
        jPanel5.add(headerInterfaceConfig);

        getContentPane().add(jPanel5);

        interfacesComboBox.setModel(new javax.swing.DefaultComboBoxModel());
        interfacesComboBox.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                interfacesComboBoxActionPerformed(evt);
            }
        });
        getContentPane().add(interfacesComboBox);

        jPanel1.setLayout(new java.awt.GridLayout(6, 2));

        dhcpCheckBox.setText("DHCP");
        dhcpCheckBox.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                dhcpCheckBoxActionPerformed(evt);
            }
        });
        jPanel1.add(dhcpCheckBox);

        onButton.setText("wyłącz");
        emptyPanel.add(onButton);

        jPanel1.add(emptyPanel);

        jLabel2.setText("IP");
        jPanel1.add(jLabel2);
        jPanel1.add(ipTextInput);

        jLabel3.setText("Maska");
        jPanel1.add(jLabel3);
        jPanel1.add(maskTextInput);

        jLabel4.setText("Brama");
        jPanel1.add(jLabel4);
        jPanel1.add(gateTextInput);

        jLabel5.setText("Wysłano");
        jPanel1.add(jLabel5);

        sentTextInput.setEditable(false);
        sentTextInput.setText("60kB");
        jPanel1.add(sentTextInput);

        jLabel6.setText("Odebrano");
        jPanel1.add(jLabel6);

        receivedTextInput.setEditable(false);
        receivedTextInput.setText("40B");
        jPanel1.add(receivedTextInput);

        getContentPane().add(jPanel1);

        jPanel4.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.RIGHT));

        saveInterfaceButton.setText("Zapisz");
        saveInterfaceButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                saveInterfaceButtonActionPerformed(evt);
            }
        });
        jPanel4.add(saveInterfaceButton);

        loadInterfaceButton.setText("Wczytaj");
        loadInterfaceButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                loadInterfaceButtonActionPerformed(evt);
            }
        });
        jPanel4.add(loadInterfaceButton);

        applyConfigButton.setText("Zastosuj konfiguracje");
        applyConfigButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                applyConfigButtonActionPerformed(evt);
            }
        });
        jPanel4.add(applyConfigButton);

        getContentPane().add(jPanel4);

        jPanel10.setLayout(new javax.swing.BoxLayout(jPanel10, javax.swing.BoxLayout.Y_AXIS));

        jPanel2.setLayout(new javax.swing.BoxLayout(jPanel2, javax.swing.BoxLayout.Y_AXIS));
        jPanel10.add(jPanel2);

        jLabel1.setFont(new java.awt.Font("Dialog", 1, 24)); // NOI18N
        jLabel1.setText("Siec bezprzewodowa");
        jPanel10.add(jLabel1);

        jPanel7.setLayout(new java.awt.GridLayout(2, 2));

        wirelessName.setText("nazwa");
        jPanel7.add(wirelessName);

        wirelessNameTextField.setEditable(false);
        wirelessNameTextField.setText("siec AGH");
        wirelessNameTextField.setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR));
        jPanel7.add(wirelessNameTextField);

        wirelessSignalStrength.setText("siła sygnału");
        jPanel7.add(wirelessSignalStrength);

        wirelessSignalStrengthTextField.setEditable(false);
        wirelessSignalStrengthTextField.setHorizontalAlignment(javax.swing.JTextField.LEFT);
        wirelessSignalStrengthTextField.setText("bardzo dobra");
        wirelessSignalStrengthTextField.setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR));
        jPanel7.add(wirelessSignalStrengthTextField);

        jPanel10.add(jPanel7);

        jPanel3.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.RIGHT));

        changeWirelessButton.setText("Zmien");
        changeWirelessButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                changeWirelessButtonActionPerformed(evt);
            }
        });
        jPanel3.add(changeWirelessButton);

        jPanel10.add(jPanel3);

        getContentPane().add(jPanel10);

        pack();
    }// </editor-fold>//GEN-END:initComponents

    private void interfacesComboBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_interfacesComboBoxActionPerformed
        
        model = (NetworkInterfaceConfig) interfacesComboBox.getSelectedItem();
        updateView();
    }//GEN-LAST:event_interfacesComboBoxActionPerformed

    private void dhcpCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_dhcpCheckBoxActionPerformed
        JCheckBox o = (JCheckBox) evt.getSource();
        model.setIpViaDHCP(o.getSelectedObjects() != null);
        updateView();
    }//GEN-LAST:event_dhcpCheckBoxActionPerformed

    private void saveInterfaceButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_saveInterfaceButtonActionPerformed
        OutputStream os = null;
        try {
            String configName = JOptionPane.showInputDialog("Nazwa konfiguracji");
            
            if(configName == null)
                return;
            
            os = new BufferedOutputStream(new FileOutputStream(new File(SelectConfigurationDialog.CONFIG_FOLDER, configName)));
            xstream.toXML(model, os);
            
            JOptionPane.showMessageDialog(null, "Konfiguracja " + configName + " zapisana poprawnie");
            
        } catch (FileNotFoundException ex) {
            Logger.getLogger(NetworkInterfaceDialog.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            try {
                if(os != null)
                    os.close();
            } catch (IOException ex) {
                Logger.getLogger(NetworkInterfaceDialog.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }//GEN-LAST:event_saveInterfaceButtonActionPerformed

    private void loadInterfaceButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_loadInterfaceButtonActionPerformed
        try {
            // FIXME czy to jest potrzebne????
            NetworkInterfaceConfig selectedItem = (NetworkInterfaceConfig) interfacesComboBox.getSelectedItem();
            
            String selectedConfig = SelectConfigurationDialog.getConfigName(null);
            
            if(selectedConfig == null)
                return;
            
            InputStream is = new BufferedInputStream(new FileInputStream(new File(SelectConfigurationDialog.CONFIG_FOLDER, selectedConfig)));
            
            NetworkInterfaceConfig config = (NetworkInterfaceConfig) xstream.fromXML(is);
            
            int n = interfacesComboBox.getItemCount();
            NetworkInterfaceConfig [] orderedConfigs = new NetworkInterfaceConfig[n];
            
            for(int i = 0; i < n; i++)
                orderedConfigs[i] = (NetworkInterfaceConfig) interfacesComboBox.getItemAt(i);
            
            NetworkInterfaceConfig comboConfig;
            for(int i = 0; i < n; i++) {    
                comboConfig = orderedConfigs[i];
                if(config.getName().equals(comboConfig.getName())) { 
                    // podmien
                    orderedConfigs[i] = config;
                    // aktualizuj informacje o stanie z aktualnej konfiguracji
                    config.setReceived(comboConfig.getReceived());
                    config.setSent(comboConfig.getSent());
                    config.setOn(comboConfig.isOn());
                    break;
                }
            }
            
            interfacesComboBox.removeAllItems();
            
            for(NetworkInterfaceConfig nic : orderedConfigs)
                interfacesComboBox.addItem(nic);
            
            interfacesComboBox.setSelectedItem(selectedItem);
            
            if (model.getName().equals(config.getName()))
                model = config;
            
            JOptionPane.showMessageDialog(null, "Konfiguracja dla interfejsu " + config.getName() + " wczytana poprawnie");
            updateView();
        } catch (FileNotFoundException ex) {
            Logger.getLogger(NetworkInterfaceDialog.class.getName()).log(Level.SEVERE, null, ex);
        }
    }//GEN-LAST:event_loadInterfaceButtonActionPerformed

    private void applyConfigButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_applyConfigButtonActionPerformed
        // TODO add your handling code here:
        List<NetworkInterfaceConfig> interfaces = new ArrayList<NetworkInterfaceConfig>();
        
        int n = interfacesComboBox.getItemCount();
        for(int i = 0; i < n; i++)
            interfaces.add((NetworkInterfaceConfig) interfacesComboBox.getItemAt(i));
        
        ConfigIO.saveConfiguration(interfaces);
        
        // restartuje network-managera
        applyConfiguration();
        
        updateView();
    }//GEN-LAST:event_applyConfigButtonActionPerformed

    private void changeWirelessButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_changeWirelessButtonActionPerformed
        
        // TODO zmiana fake'a na interfejs
        WirelessInterfaceConfig wic = new WirelessInterfaceConfig();
        wic.setName("wlan0");
        
        WirelessNetwork selectedNetwork = SelectWirelessNetworkDialog.getWirelessNetwork(null, wic);
        if(selectedNetwork == null)
            return;
        
        // TODO zrob mnie
    }//GEN-LAST:event_changeWirelessButtonActionPerformed

    private static void applyConfiguration() {
        ShellExecutor.executeSynchronouslyAsRoot("service network-manager restart");
    }
    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        /*
         * Set the Nimbus look and feel
         */
        //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
        /*
         * If Nimbus (introduced in Java SE 6) is not available, stay with the
         * default look and feel. For details see
         * http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
         */
        try {
            for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(info.getName())) {
                    javax.swing.UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        } catch (ClassNotFoundException ex) {
            java.util.logging.Logger.getLogger(NetworkInterfaceDialog.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (InstantiationException ex) {
            java.util.logging.Logger.getLogger(NetworkInterfaceDialog.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            java.util.logging.Logger.getLogger(NetworkInterfaceDialog.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (javax.swing.UnsupportedLookAndFeelException ex) {
            java.util.logging.Logger.getLogger(NetworkInterfaceDialog.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }
        //</editor-fold>

        /*
         * Create and display the dialog
         */
        java.awt.EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                NetworkInterfaceDialog dialog = new NetworkInterfaceDialog(new javax.swing.JFrame(), true);
                dialog.addWindowListener(new java.awt.event.WindowAdapter() {

                    @Override
                    public void windowClosing(java.awt.event.WindowEvent e) {
                        System.exit(0);
                    }
                });
                dialog.setVisible(true);
            }
        });
    }
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton applyConfigButton;
    private javax.swing.JButton changeWirelessButton;
    private javax.swing.JCheckBox dhcpCheckBox;
    private javax.swing.JPanel emptyPanel;
    private javax.swing.JTextField gateTextInput;
    private javax.swing.JLabel headerInterfaceConfig;
    private javax.swing.JComboBox interfacesComboBox;
    private javax.swing.JTextField ipTextInput;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JLabel jLabel3;
    private javax.swing.JLabel jLabel4;
    private javax.swing.JLabel jLabel5;
    private javax.swing.JLabel jLabel6;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JPanel jPanel10;
    private javax.swing.JPanel jPanel2;
    private javax.swing.JPanel jPanel3;
    private javax.swing.JPanel jPanel4;
    private javax.swing.JPanel jPanel5;
    private javax.swing.JPanel jPanel7;
    private javax.swing.JButton loadInterfaceButton;
    private javax.swing.JTextField maskTextInput;
    private javax.swing.JButton onButton;
    private javax.swing.JTextField receivedTextInput;
    private javax.swing.JButton saveInterfaceButton;
    private javax.swing.JTextField sentTextInput;
    private javax.swing.JLabel wirelessName;
    private javax.swing.JTextField wirelessNameTextField;
    private javax.swing.JLabel wirelessSignalStrength;
    private javax.swing.JTextField wirelessSignalStrengthTextField;
    // End of variables declaration//GEN-END:variables

    private void addFocusListeners() {
        ipTextInput.addFocusListener(new FocusListener() {

            @Override
            public void focusGained(FocusEvent fe) {
                ipAddressFocusListener.focusGained(fe);
            }

            @Override
            public void focusLost(FocusEvent fe) {
                ipAddressFocusListener.focusLost(fe);
            }
        });
        
        maskTextInput.addFocusListener(new FocusListener() {

            @Override
            public void focusGained(FocusEvent fe) {
                maskAddressFocusListener.focusGained(fe);
            }

            @Override
            public void focusLost(FocusEvent fe) {
                maskAddressFocusListener.focusLost(fe);
            }
        });
        
        gateTextInput.addFocusListener(new FocusListener() {

            @Override
            public void focusGained(FocusEvent fe) {
                gateAddressFocusListener.focusGained(fe);
            }

            @Override
            public void focusLost(FocusEvent fe) {
                gateAddressFocusListener.focusLost(fe);
            }
        });
    }

}
